package com.dongdong.bookstore.module.ums.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dongdong.bookstore.common.exception.Asserts;
import com.dongdong.bookstore.module.ums.mapper.ResourceMapper;
import com.dongdong.bookstore.module.ums.mapper.RoleMapper;
import com.dongdong.bookstore.module.ums.model.Admin;
import com.dongdong.bookstore.module.ums.mapper.AdminMapper;
import com.dongdong.bookstore.module.ums.model.Resource;
import com.dongdong.bookstore.module.ums.model.Role;
import com.dongdong.bookstore.module.ums.service.AdminRoleRelationService;
import com.dongdong.bookstore.module.ums.service.AdminService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dongdong.bookstore.module.ums.service.UmsCacheService;
import com.dongdong.bookstore.module.ums.viewmodel.AdminRegistParam;
import com.dongdong.bookstore.module.ums.viewmodel.AdminWithLastLoginTime;
import com.dongdong.bookstore.module.ums.viewmodel.UpdateAdminPasswordParam;
import com.dongdong.bookstore.security.model.CustomUserDetails;
import com.dongdong.bookstore.security.model.UserCategory;
import com.dongdong.bookstore.security.utils.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 * 管理员表 服务实现类
 * </p>
 *
 * @author chiangkai
 * @since 2021-10-20
 */
@Service
@Slf4j
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    //    @Autowired
//    private AdminLoginLogMapper loginLogMapper;
    @Autowired
    private UmsCacheService umsCacheService;
    @Autowired
    private AdminRoleRelationService adminRoleRelationService;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private ResourceMapper resourceMapper;

    @Override
    public Admin register(AdminRegistParam param) {
        Admin admin = new Admin();
        BeanUtils.copyProperties(param, admin);
        QueryWrapper<Admin> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Admin::getUsername, param.getUsername());
        Integer count = baseMapper.selectCount(wrapper);
        Asserts.gt0(count, "此用户已存在，添加管理员失败");
        admin.setPassword(passwordEncoder.encode(param.getPassword()));
        int insert = baseMapper.insert(admin);
        if (insert > 0) {
            return baseMapper.selectOne(wrapper);
        }
        Asserts.fail("添加管理员失败");
        return null;
    }

    @Override
    public Long registerGetId(AdminRegistParam param) {
        return register(param).getId();
    }

    @Override
    public String login(String username, String password) {
        UserDetails userDetail = loadUserByName(username);
        Asserts.isFalse(passwordEncoder.matches(password, userDetail.getPassword()), "用户名或密码错误");
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetail, null, userDetail.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        return jwtTokenUtil.generateToken(userDetail);
    }


    @Override
    public UserDetails loadUserByName(String username) {
        Admin admin = getAdminByUsername(username);
        if (admin == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        List<Resource> resources = getResourcList(admin.getId());
        admin.setUserCategory(UserCategory.ADMIN);
        admin.setUsername("admin:" + admin.getUsername());
        return new CustomUserDetails(admin, resources);
    }

    @Override
    public String refreshToken(String token) {
        return jwtTokenUtil.refreshHeadToken(token);
    }

    @Override
    public IPage<AdminWithLastLoginTime> list(String keyword, Integer pageSize, Integer pageNum) {
        Page<AdminWithLastLoginTime> page = new Page<>(pageNum, pageSize);
        QueryWrapper<AdminWithLastLoginTime> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<AdminWithLastLoginTime> lambda = wrapper.lambda();
        lambda.eq(AdminWithLastLoginTime::getDeleted, 0);
        if (StrUtil.isNotEmpty(keyword)) {

            lambda.like(AdminWithLastLoginTime::getUsername, keyword);
            lambda.or().like(AdminWithLastLoginTime::getNickName, keyword);
        }
        IPage<AdminWithLastLoginTime> result = adminMapper.getListWithLastLoginTime(page, wrapper);
        return result;

    }

    @Override
    public boolean update(Long id, Admin admin) {
        admin.setId(id);
        Admin rawAdmin = getById(id);
        if (rawAdmin.getPassword().equals(admin.getPassword())) {
            //与原加密密码相同的不需要修改
            admin.setPassword(null);
        } else {
            //与原加密密码不同的需要加密修改
            if (StrUtil.isEmpty(admin.getPassword())) {
                admin.setPassword(null);
            } else {
                admin.setPassword(passwordEncoder.encode(admin.getPassword()));
            }
        }
        boolean success = updateById(admin);
        if (success) {
            umsCacheService.delAdmin(id);
            umsCacheService.setAdmin(admin);
        }
        return success;
    }

    @Override
    public void updatePassword(UpdateAdminPasswordParam updateAdminPasswordParam) {
        Admin admin = getAdminByUsername(updateAdminPasswordParam.getUsername());
        Asserts.isNull(admin, "管理员不存在");
        Asserts.isFalse(passwordEncoder.matches(updateAdminPasswordParam.getOldPassword(), admin.getPassword()), "旧密码错误");
        admin.setPassword(passwordEncoder.encode(updateAdminPasswordParam.getNewPassword()));
        Asserts.isFalse(updateById(admin), "密码更新失败");
    }

    @Override
    public List<Role> getRoleList(Long adminId) {
        return roleMapper.getRoleList(adminId);
    }

    @Override
    public boolean delete(Long id, String username) {
        Admin delAdmin = getById(id);
        Asserts.isNull(delAdmin, "删除的用户不存在");
        Admin admin = umsCacheService.getAdmin(username);
        Asserts.isTrue(admin.getId().equals(delAdmin.getId()), "不能删除当前用户");
        // 防止逻辑删除后影响唯一索引
        delAdmin.setUsername("deleted:" + delAdmin.getId() + "$$" + delAdmin.getUsername());
        umsCacheService.delAdmin(delAdmin.getUsername());
        updateById(delAdmin);
        return removeById(delAdmin.getId());
    }

    private List<Resource> getResourcList(Long id) {
        List<Resource> resourceList = umsCacheService.getResourceList(id);
        if (CollUtil.isEmpty(resourceList)) {
            resourceList = resourceMapper.getResouceListByAdminId(id);
            if (CollUtil.isNotEmpty(resourceList)) {
                umsCacheService.setResourceList(id, resourceList);
            }
        }
        return resourceList;
    }


    @Override
    public void judgeAdminExist(String username) {
        Asserts.notNull(getAdminByUsername(username), "此管理员用户已存在");
    }

    @Override
    public Admin getAdminByUsername(String username) {
        Admin admin = umsCacheService.getAdmin(username);
        if (admin == null) {
            QueryWrapper<Admin> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(Admin::getUsername, username);
            admin = baseMapper.selectOne(wrapper);
            if (admin != null) {
                umsCacheService.setAdmin(admin);
            }
        }
        return admin;
    }
}
